package com.yequan.drawerlayoutdemo.skin;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.AsyncTask;

import com.yequan.drawerlayoutdemo.skin.attrs.SkinView;
import com.yequan.drawerlayoutdemo.skin.callback.ISkinChangedListener;
import com.yequan.drawerlayoutdemo.skin.callback.ISkinChangingCallback;
import com.yequan.drawerlayoutdemo.utils.PrefUtils;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2017/2/9 0009.
 */

public class SkinManager {
    private Context mContext;
    private volatile static SkinManager sInstance;
    private ResourcesManager mResourcesManager;

    private List<ISkinChangedListener> mListeners = new ArrayList<>();

    private Map<ISkinChangedListener, List<SkinView>> mSkinViewMaps = new HashMap<>();

    private PrefUtils mPrefUtils;
    private String mCurrPath;
    private String mCurrPkg;
    private String mSuffix;
    private Boolean usePlugin = false;

    private SkinManager() {

    }

    public static SkinManager getInstance() {
        if (sInstance == null) {
            synchronized (SkinManager.class) {
                if (sInstance == null) {
                    sInstance = new SkinManager();
                }
            }
        }
        return sInstance;
    }

    public ResourcesManager getResourceManager() {
        if (!usePlugin) {
            return new ResourcesManager(mContext.getResources(), mContext.getPackageName(), mSuffix);
        }
        return mResourcesManager;
    }

    public void init(Context context) {
        mContext = context.getApplicationContext();
        mPrefUtils = new PrefUtils(mContext);
        String pluginPath = mPrefUtils.getPluginPath();
        String pluginPkg = mPrefUtils.getPluginPkg();
        mSuffix = mPrefUtils.getSuffix();
        File file = new File(pluginPath);
        if (file.exists()) {
            try {
                loadPlugin(pluginPath, pluginPkg);
                mCurrPath = pluginPath;
                mCurrPkg = pluginPkg;
            } catch (Exception e) {
                e.printStackTrace();
                mPrefUtils.clear();
            }
        }
    }

    private void loadPlugin(String skinPluginPath, String skinPluginPkg) throws Exception {
        if (skinPluginPath.equals(mCurrPath) && skinPluginPkg.equals(mCurrPkg))
            return;
        AssetManager assetManager = AssetManager.class.newInstance();
        Method addAssetPathMethod = assetManager.getClass().getMethod("addAssetPath", String.class);
        addAssetPathMethod.invoke(assetManager, skinPluginPath);

        Resources superResources = mContext.getResources();
        Resources resources = new Resources(assetManager, superResources.getDisplayMetrics(), superResources.getConfiguration());
        mResourcesManager = new ResourcesManager(resources, skinPluginPkg, null);
        usePlugin = true;
    }

    public List<SkinView> getSkinViews(ISkinChangedListener listener) {
        return mSkinViewMaps.get(listener);
    }

    public void addSkinView(ISkinChangedListener listener, List<SkinView> skinViews) {
        mSkinViewMaps.put(listener, skinViews);
    }

    public void registerListener(ISkinChangedListener listener) {
        mListeners.add(listener);
    }

    public void unRegisterListener(ISkinChangedListener listener) {
        mListeners.remove(listener);
        mSkinViewMaps.remove(listener);
    }


    public void changeSkin(final String skinPluginPath, final String skinPluginPkg, ISkinChangingCallback callback) {
        if (callback == null) {
            callback = ISkinChangingCallback.DEFAULT_CALLBACK;
        }
        final ISkinChangingCallback finalCallback = callback;
        finalCallback.onStart();
        new AsyncTask<Void, Void, Integer>() {
            @Override
            protected Integer doInBackground(Void... params) {
                try {
                    loadPlugin(skinPluginPath, skinPluginPkg);
                } catch (Exception e) {
                    e.printStackTrace();
                    finalCallback.onError(e);
                    return -1;
                }
                return 0;
            }

            @Override
            protected void onPostExecute(Integer code) {
                if (code == -1) {
                    finalCallback.onError(null);
                    return;
                }
                try {
                    notifyChangedListener();
                    finalCallback.onComplete();
                    updatePluginInfo(skinPluginPath, skinPluginPkg);
                } catch (Exception e) {
                    e.printStackTrace();
                    finalCallback.onError(e);
                }
            }
        }.execute();
    }

    public void changeSkin(String suffix) {
        clearPluginInfo();
        mSuffix = suffix;
        mPrefUtils.saveSuffix(suffix);
        notifyChangedListener();
    }

    private void clearPluginInfo() {
        mCurrPath = null;
        mCurrPkg = null;
        usePlugin = false;
        mSuffix = null;
        mPrefUtils.clear();
    }

    private void updatePluginInfo(String path, String pkg) {
        mPrefUtils.savePluginPath(path);
        mPrefUtils.savePluginPkg(pkg);
    }

    private void notifyChangedListener() {
        for (ISkinChangedListener listener : mListeners) {
            skinChange(listener);
            listener.onSkinChanged();
        }
    }

    public void skinChange(ISkinChangedListener listener) {
        List<SkinView> skinViews = mSkinViewMaps.get(listener);
        for (SkinView skinView : skinViews) {
            skinView.apply();
        }
    }

    public void removeAnySkin() {
        clearPluginInfo();
        notifyChangedListener();
    }

    public boolean needChangeSkin() {
        return usePlugin || useSuffix();
    }

    private boolean useSuffix() {
        return mSuffix != null && !mSuffix.trim().equals("");
    }
}
